package Communication;

import DecUtil.utilities;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.net.telnet.TelnetClient;
/**
 *
 * @author mgrutman
 */
public class MyTelnet 
{
    PrintStream fOut = null;
    InputStream fIn = null;
    Socket fSocket = null;
    String sres = "";
    TelnetClient tc = new TelnetClient();
    final char escape = '\u001D';
    
    boolean sessionRunning = false; 
    
    String username,password,prompt;
        
    public int myPing (String server, int port)
    {
        try
        {
            tc.connect(server);
            return tc.isConnected()? 1 : 0;
        }
        catch (SocketException ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        } 
        catch (Exception ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE, null, ex);
            return -2;
        }
    }
    /**
     * Initiates a telnet connection to given server address.
     * @param server
     * Port at which to connect with. Not used at present.
     * @param port
     * @return 
     */
    public boolean initializeCommunicationTo (String server, int port)
    {
        try
        {
            tc.connect(server, port);
            fIn = tc.getInputStream();
            fOut = new PrintStream(tc.getOutputStream());            
            return true; 
        } 
        catch (UnknownHostException ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IOException ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false; 
    }
    
    /**
     * Reads the input stream till we find a character string similar to prompt>
     * if prompt's value is switch, "switch>", "switch000>" all of them match this.
     * @param prompt
     * @return 
     */
    public String readTillPrompt(String prompt)
    {
        Pattern regex = Pattern.compile(".*"+prompt+".*>");
        StringBuffer sb = new StringBuffer(""); 
        
        try
        { 
            Matcher m;             
            
            while (fIn.available() > 0)
            {
                sb.append((char)fIn.read()); 
                m = regex.matcher(sb.toString());
                if(m.matches())
                {
                    Logger.getLogger(MyTelnet.class.getName()).log(Level.INFO,sb.toString());
                    return sb.toString();
                }
            }
        }
        catch ( IOException ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.INFO,sb.toString());
        }
        catch (Exception ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE,ex.toString());
        }
        
        return sb.toString();
    }
    
    /**
     * Reads all the characters written to input stream and returns them as a string.
     * @return 
     */
    public String readAvailable()
    {
        StringBuffer sb = new StringBuffer(""); 
        byte buffer[] = new byte[256];
        int count; 
        
        try
        { 
            while ((count = fIn.available()) > 0)
            {
                if(count > 256 )
                {
                    fIn.read(buffer, 0, 256);
                }
                else
                {
                    fIn.read(buffer,0,count);
                }
                
                sb.append(new String(buffer,"UTF-8")); 
            }
        }
        catch ( IOException ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.INFO,sb.toString());
        }
        catch (Exception ex)
        {
            Logger.getLogger(MyTelnet.class.getName()).log(Level.SEVERE,ex.toString());
        }
        
        return sb.toString();
    }
    
    /**
     * @param username
     * username to use for the switch.
     * @param password
     * password to the switch
     * @param prompt 
     * resulting prompt if we are successful.
     */
       
    public void loginEthernetSwitch (String username, String password,String prompt)
    {
        fOut.println(username+"\r\n");
        fOut.flush();
        utilities.sleep(1000);
        readAvailable();
        
        fOut.println(password+"\r\n"); 
        fOut.flush();
        utilities.sleep(1000);
        readAvailable();
        
        sessionRunning = true; 
    }
    
    /**
     * Returns a boolean indicating telnet session's successful connection. 
     *  True  - connected to the IP
     *  False - Not connected.
     * @return 
     */
    public final boolean sessionRunning()
    {
        return sessionRunning; 
    }
    
    /**
     * Function to run a file containing commands.
     * @param fname absolute path to the file.
     */
    public void runTelnetFile  (String fname)
    {
        ExeTelnetFromText et = new ExeTelnetFromText();
        
        String cmds [] = et.readCmdListFromFile(fname);
        
        for (int i = 0; i < cmds.length; ++i)
        {
            fOut.println(cmds [i]); fOut.flush();
            readTillPrompt("Manager");
        }
    }
     
    /**
     * @param commands 
     */
    public void runTelnetCommands (final String commands[])
    {
        for(String command : commands)
        {
            fOut.println(command + "\r\n");            
        }
    }
    /**
     * Runs a telnet command and returns text from other side. 
     * This functions sleeps for a second to allow other end to respond. 
     * @param command
     * @return 
     */
    public String runTelentCommand(final String command)
    {
        fOut.println(command + "\r\n");
        
        utilities.sleep(escape);
        
        return readAvailable();
    }
    /**
     * sends a ctrl+] character to the telnet session to indicate ending of session. 
     * gives a quit command to exit telnet application on hosts (our) end.
     * @return 
     */    
    public boolean disconnect()
    {
        try 
        {
            fOut.print(escape);
            fOut.flush();            
            System.out.println(readTillPrompt("telnet"));            
            fOut.print("quit\r\n");
            fOut.flush();
            tc.disconnect();
            return true;
        }
        catch ( Exception ex)
        {
            return false; 
        }    
    }
}  